from polyhedron import Polyhedron        


class BN(Polyhedron):
    
    #偶数多面体顶点相邻的连续3顶点
    h3_dict = dict([(v,i) for i,v in enumerate(['464','466','468','484','486',
        '488','646','648','666','668','686','688','848','868','888'])]) #15个
        
    @staticmethod
    def permut_feature(permut):
        '''根据邻接点圆排列计算顶点特征向量'''
        permut = permut + permut[:2]
        feature = np.zeros((15,), dtype='float')
        for i in range(len(permut)-2):
            str1, str2 = ''.join([str(_) for _ in permut[i:i+3]]), ''.join([str(_) for _ in reversed(permut[i:i+3])])
            feature[BN.h3_dict[min(str1,str2)]] += 1
        return feature
        
    def v3_feature(self, v=None):
        '''顶点特征，15维向量'''
        if v is None:
            feature = np.empty((len(self.at),15), dtype='float')
            for i in range(len(self.at)):
                feature[i] = BN.permut_feature([self.degree(x) for x in self.at[i]])
            return feature
        else:
            return BN.permut_feature([self.degree(x) for x in self.at[v]])
    
    def alternate_elem(self, c, elem2):
        '''给团簇c的原子交替赋元素。元素1已赋值'''
        e1, e2 = set([0]), set()
        curr1 = set([0])
        flag = [False] * len(self.at)
        while len(e1) + len(e2) < len(self.at):
            curr2 = set()
            for v in curr1:
                if not flag[v]:
                    curr2 = curr2 | set(self.at[v])
                    flag[v] = True
            e2 = e2 | curr2
            curr1 = curr2
            e1, e2 = e2, e1
        for v in e2:
            c[v].elem = elem2

    def gen_coo(self, elem='B', elem2='N'):
        '''由拓扑结构生成三维坐标
        返回：团簇'''
        Polyhedron.gen_coo(self, elem)
        self.alternate_elem(c, elem2)
        c.zoom(Periodic_Table.bond_len(elem, elem2))
        return c

    def iso_quadrangle(self):
        '''是否隔绝四边形
        self:三角多面体'''
        for nei in self.at:
            if len(nei)==4:
                for v in nei:
                    if len(self.at[v]) == 4:
                        return False
        return True
        
    def iso4_468(self):
        """隔绝四边形且只有4,6,8边形构成"""
        for nei in self.at:
            if len(nei) > 8:
                return False
            elif len(nei) == 4:
                for v in nei:
                    if len(self.at[v]) == 4:
                        return False
        return True
        
    def max_dist4(self):
        '''四元环最大距离'''
        d = self.dist()
        v4 = list(filter(lambda v:self.degree(v)==4, range(len(self.at))))
        return min([d[p,q] for i,p in enumerate(v4) for q in v4[:i]])
          
         
def to_xsd_all(file_name):
    '''从邻接表文件中读取所有三角多面体，并保存成xsd'''
    f = open(file_name)
    count = 0
    while True:
        p = BN.from_txt(f)
        if p is None:
            break
        count += 1
        print(count)
        p.to_cluster('C116\\C116_%04d.xsd'%count)
    
    
def tri2ai(file_name, n): 
    """三角多面体结构保存邻接矩阵、顶点哈希
    file_name: 邻接表格式的三角多面体文件
    n: 三角多面体顶点数""" 
    I = [] #顶点哈希
    A = [] #邻接矩阵
    f = open(file_name)
    m = 0 #个数
    while True:
        p = BN.from_txt(f)
        if p is None:
            break
        I.append(np.array([BN.hash468_dict[p._vertex_hash(v)] for v in range(n)]))
        A.append(p.to_adj())
        m += 1
    print('有%d个结构'%m)
    
    I = np.stack(I)
    print(set(I.ravel()))
    A = np.stack(A)
    np.savez('tri%d_ai.npz'%n, A=A, I=I)
    